#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <strings.h>
#include <iostream> 

#include "threadpool.h"

using namespace std;

Tpool *create_threadpool(int size_thr,int size_maxtask){
	Tpool * tp;
	tp = (Tpool *)malloc(sizeof(Tpool));

	tp->thr_cnt = size_thr;
	tp->MAXN = size_maxtask;
	tp->shutdown = 0;
	tp->cnt = 0;
	tp->hd = 0;
	tp->tail = 0;
	tp->task = (Event*)malloc((sizeof(Event)*size_maxtask));
	pthread_mutex_init(&(tp->pool_mutex),NULL);
	pthread_mutex_init(&(tp->write_mutex),NULL);
	pthread_cond_init(&(tp->empty_task),NULL);
	pthread_cond_init(&(tp->unempty_task),NULL);

	tp->thr = (pthread_t *)malloc((sizeof(pthread_t*)*size_thr));

	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

	for(int i=0;i<size_thr;i++){
		pthread_create(&(tp->thr[i]),&attr,thr_start,(void*)tp);
	}

	return tp;
}


void *thr_start(void *arg){
	Tpool *tp = (Tpool *)arg;
	int pos = 0;
	Event *task = (Event*)malloc(sizeof(Event));
	
	
	while(1){
		//lock
		pthread_mutex_lock(&(tp->pool_mutex));
		//printf("22\n");
		while(tp->cnt<=0 && tp->shutdown == 0){
			pthread_cond_wait(&tp->unempty_task,&tp->pool_mutex);
		}
		
		if(tp->cnt>0){
			pos = (tp->hd++)%tp->MAXN;
			memcpy(task,&tp->task[pos],sizeof(Event));
			
			tp->cnt--;
			pthread_cond_signal(&tp->empty_task);
		}

		if(tp->shutdown == 2){
			pthread_mutex_unlock(&tp->pool_mutex);
			free(task);
			pthread_exit(NULL);
		}

		pthread_mutex_unlock(&tp->pool_mutex);

		char *reback = (char *)malloc(sizeof(char)*50);
		memset(reback,0,sizeof(reback));
		task->func(task->opstr,task->fd,reback);
		
		pthread_mutex_lock(&tp->write_mutex);
		write(task->fd,reback,sizeof(char)*strlen(reback));
		write(task->fd,"\n----------------------\n",sizeof("\n----------------------\n"));
		printf("------------------------------------------------START\n");
		printf("receive : %s\n resuls : %s\n",task->opstr,reback);
		printf("------------------------------------------------END\n");
		pthread_mutex_unlock(&tp->write_mutex);

		free(reback);
	}
}


void close_threadpool(Tpool *tp){
	tp->shutdown = 1;
	pthread_cond_broadcast(&tp->unempty_task);
	
/*
	for(int i=0;i<tp->thr_cnt;i++){
		pthread_join(tp->thr[i],NULL);
}
*/
	pthread_cond_destroy(&tp->empty_task);
	pthread_cond_destroy(&tp->unempty_task);
	pthread_mutex_destroy(&tp->pool_mutex);
	pthread_mutex_destroy(&tp->write_mutex);
	free(tp->task);
	free(tp->thr);
	free(tp);
}

void thread_addtask(Tpool *tp,int fd,char* opstr,void (*taskfunc)(char *,int,char *)){
	pthread_mutex_lock(&tp->pool_mutex);

	while(tp->cnt >= tp->MAXN){
		pthread_cond_wait(&tp->empty_task,&tp->pool_mutex);
	}
	
	int pos = (tp->tail++)%tp->MAXN;
	tp->task[pos].func = taskfunc;
	tp->task[pos].fd = fd;
	//tp->task[pos].opstr = opstr.substr();
	//astrcpy(&tp->task[pos].opstr,&opstr);
	tp->task[pos].opstr = opstr;
	tp->cnt++;	
	pthread_mutex_unlock(&tp->pool_mutex);

	pthread_cond_signal(&tp->unempty_task);
}


